package com.iwhalecloud.citybrain.flow.platform.manager.application.utils;

import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.NextNodeWithGatewayParamKey;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.*;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author: liyang
 * @date: 2021/12/24 16:46
 */
public class FlowGatewayTravller {

    private FlowGatewayTravller() {
    }


    public FlowGatewayTravller(String patternReg) {
        pattern = Pattern.compile(patternReg);
    }

    /**
     * 人工选择节点时，网关连接线参数的匹配正则表达式
     */
    private Pattern pattern;

    public void travllToTargetNode(FlowElement flowElement, List<NextNodeWithGatewayParamKey> nextNodeWithGatewayParamKeyList, FlowGatewayExpressKeyContext gatewayContext) {
        if (flowElement instanceof FlowNode) {

            FlowNode flowNode = (FlowNode) flowElement;
            List<SequenceFlow> outgoingFlows = flowNode.getOutgoingFlows();
            if (CollectionUtils.isNotEmpty(outgoingFlows)) {
                for (SequenceFlow outgoingFlow : outgoingFlows) {
                    String expression = outgoingFlow.getConditionExpression();
                    FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();

                    //表达式为空，一定会走该节点
                    if (StringUtils.isBlank(expression)) {
                        checkFlowElement(targetFlowElement, new HashSet<>(), nextNodeWithGatewayParamKeyList, gatewayContext);
                    } else {
                        Set<String> paramKey = new HashSet<>();
                        Matcher matcher = pattern.matcher(expression);
                        while (matcher.find()) {
                            String findResult = matcher.group(0).trim();
                            paramKey.add(findResult);
                        }
                        checkFlowElement(targetFlowElement, paramKey, nextNodeWithGatewayParamKeyList, gatewayContext);
                    }
                }
            }
        }
    }

    public void checkFlowElement(FlowElement flowElement, Set<String> paramKey, List<NextNodeWithGatewayParamKey> nextNodeWithGatewayParamKeyList, FlowGatewayExpressKeyContext parentGatewayContext) {
        //用户节点
        if (flowElement instanceof UserTask) {
            UserTask userTask = (UserTask) flowElement;
            NextNodeWithGatewayParamKey nextNodeWithGatewayParamKey = new NextNodeWithGatewayParamKey();
            nextNodeWithGatewayParamKey.setNodeCode(userTask.getId());
            nextNodeWithGatewayParamKey.setNodeName(userTask.getName());
            paramKey = getAllParamKey(paramKey, parentGatewayContext);
            nextNodeWithGatewayParamKey.setGatewayParamKey(paramKey);
            nextNodeWithGatewayParamKeyList.add(nextNodeWithGatewayParamKey);
        } else if ((flowElement instanceof InclusiveGateway)
                || (flowElement instanceof ExclusiveGateway)) {
            //包含网关或排他网关
            FlowGatewayExpressKeyContext gatewayContext = new FlowGatewayExpressKeyContext();
            gatewayContext.setParamKeySet(paramKey);
            gatewayContext.setParentContext(parentGatewayContext);
            travllToTargetNode(flowElement, nextNodeWithGatewayParamKeyList, gatewayContext);
        } else if (flowElement instanceof EndEvent) {
            // 结束节点
            EndEvent endEvent = (EndEvent) flowElement;
            NextNodeWithGatewayParamKey nextNodeWithGatewayParamKey = new NextNodeWithGatewayParamKey();
            nextNodeWithGatewayParamKey.setNodeCode(endEvent.getId());
            nextNodeWithGatewayParamKey.setNodeName(endEvent.getName());
            paramKey = getAllParamKey(paramKey, parentGatewayContext);
            nextNodeWithGatewayParamKey.setGatewayParamKey(paramKey);
            nextNodeWithGatewayParamKeyList.add(nextNodeWithGatewayParamKey);
        } else if (flowElement instanceof ParallelGateway) {
            //包含并行网关
            ParallelGateway parallelGateway = (ParallelGateway) flowElement;
            NextNodeWithGatewayParamKey nextNodeWithGatewayParamKey = new NextNodeWithGatewayParamKey();
            nextNodeWithGatewayParamKey.setNodeCode(parallelGateway.getId());
            nextNodeWithGatewayParamKey.setNodeName(parallelGateway.getName());
            paramKey = getAllParamKey(paramKey, parentGatewayContext);
            nextNodeWithGatewayParamKey.setGatewayParamKey(paramKey);
            nextNodeWithGatewayParamKeyList.add(nextNodeWithGatewayParamKey);
        }
    }

    private Set<String> getAllParamKey(Set<String> paramKey, FlowGatewayExpressKeyContext parentGatewayContext) {
        if (Objects.nonNull(parentGatewayContext)) {
            Set<String> paramKeySet = parentGatewayContext.getParamKeySet();
            if (CollectionUtils.isNotEmpty(paramKeySet)) {
                paramKey.addAll(paramKeySet);
            }
            if (Objects.nonNull(parentGatewayContext.getParentContext())) {
                paramKey.addAll(getAllParamKey(paramKey, parentGatewayContext.getParentContext()));
            }
        }
        return paramKey;
    }

}
